
/* 

Please, forgive the messiness of the code... it was created 
afterhours, under extreme time contraints, few days before
Google I/O. Hope that, even messy, it inspires you to improve it
and use it somewhere else. All of it is licensed under MIT 
License

Author: Renato Mangini/@renatomangini - GTUG Belo Horizonte

*/

// this must be global, so that earth.js can read it
var timeDirection=0;  // -1, 0, 1 (moving backwards, stopped, moving forwards)
var map_width, map_height, map_bg_height;

function sketch(processing) {
	/* @pjs preload="../img/map.png"; */

	var secondsOfAnimation=2, maxRadius=50, bg;
	var loaded=false;
	var curTime;
	var minIndex=0, maxIndex=-1;
	var chapters, chaptersOnMap={}, events=[];
  var numEvents=0;
  var lastPointAdded=0;
  var numChaptersAdded=0;
  
  function initVars() {
    curTime=events[0]?events[0].time:null;
    minIndex=0; maxIndex=-1;
    chaptersOnMap={};
    numEvents=0;
    lastPointAdded=0;
    numChaptersAdded=0;
    for (var i=0; i<events.length; i++) {
      events[i].steps=0;
    }
    for (var i in chapters) {
      chapters[i].addedToEarth=false;
    }
  }
      
	function parseDate(d) {
	  return new Date(d).getTime();
	}
	
	function formatDate(date) {
    var d = date.getDate();
    d = "" + (d < 10 ? "0" : "") + d + " ";
    d += "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(/ /)[date.getMonth()] + " ";
    return d;
  }
	  
  function formatTime(date) {
    var h = date.getHours();
    var ampm = h >= 12 ? "PM" : "AM";
    var t = "" + (h == 0 ? 12 : (h > 12 ? h - 12 : h)) + ":";
    var m = date.getMinutes();
    t += "" + (m < 10 ? "0" : "") + m + " " + ampm;
    return t;
  }
	  
  function updateLabels() {
    var now=new Date(curTime);
	  $(".date").text(formatDate(now));
	  $(".year").text(now.getFullYear());
	  $(".numEvents").text(numEvents+" event"+(numEvents>1?"s":""));
    $(".numChapters").text(numChaptersAdded+" chapter"+(numChaptersAdded>1?"s":""));
  }  

	processing.setup= function() {
	  processing.size( map_width, map_height );  
	  processing.strokeWeight( 5 );  
	  processing.frameRate( 10 );
	  numberOfFrames=10*secondsOfAnimation;
	  var bgName="img/map_"+map_bg_height+".png";
	  bg=processing.loadImage(bgName);  
	  $.ajax({
//		url:"http://www.gtugs.org/events?all",
//		dataType: "jsonp",
		url:"events",
		dataType: "json",
		success: function(data){
		  events=[];
		  chapters=[];
		  var i=0;
		  var _now=new Date().getTime();
		  $.each(data.events, function(index, el) {
		    if (!/UTC \d{4}/.test(el.startDate)) {
		      // this is to avoid future dates and a single invalid event record
		      // that was messing everything up because year is set to 0010, instead of 2010
		     return;
		    }
			  var eventDate=parseDate(el.startDate);
			  if (eventDate>_now)  {
				  return;
			  }
			  events[i++]={
				    time: eventDate, 
				    steps: 0,
				    chapterId: el.chapterId
			    };
			  if (typeof(chapters[el.chapterId])=='undefined') {
				  chapters[el.chapterId]={lat: el.latitude, lon: el.longitude, 
				      info: {chName: el.chapterName, city: el.city, state: el.state, 
				        country: el.country, status: el.chapterStatus}};
				  addChapterToChapterList(el.chapterId, chapters[el.chapterId]);
			  }
		  });
		  postProcessChapterList();
		  curTime=events[0].time;
		  loaded=true;
		}});
	};

  processing.drawChapter=function(chapterId, chapter) {
    var coords=processing.getCoordinates(chapter);
    processing.ellipse( coords.x, coords.y, 1, 1 );
	  if (!chapter.addedToEarth) {
		smallEarth.addPoint({id: chapterId, lat:chapter.lat, lon:chapter.lon});
		chapter.addedToEarth=true;
		numChaptersAdded++;
	  }
  };
  
  var dot_size = 3;
  var longitude_shift = -20;   // number of pixels your map's prime meridian is off-center.
  var y_pos = 48;
  var half_dot = Math.floor(dot_size / 2);
  
  processing.convertMercator=function(coords) {
    // longitude: just scale and shift
    x = (map_width * (180 + coords.lon) / 360 + longitude_shift) % map_width;

    // latitude: using the Mercator projection
    coords.lat = coords.lat * Math.PI / 180;  // convert from degrees to radians
    y = Math.log(Math.tan((coords.lat/2) + (Math.PI/4)));  // do the Mercator projection (w/ equator of 2pi units)
    y = (map_height / 2) - (map_width * y / (2 * Math.PI)) + y_pos;   // fit it to our map

    return {x: x-half_dot, y: y-half_dot};
  }

  processing.getCoordinates=function(chapter) {
	      if (!chapter.coords) {
	  	    chapter.coords=this.convertMercator({lon: chapter.lon, lat: chapter.lat});
  	    }
		    return chapter.coords;
  };
  
	processing.draw=function() { 
	  if (!timeDirection) {
	    return;
	  }
	  if (timeDirection<0) {
	    this.reverseLoop();
	    return;
	  }
	  
	  if (typeof(events)=='undefined' || events.length==0) {
	    // events not loaded yet
	    return;
	  }
    
    var _today=new Date().getTime();
    
    updateLabels();

    if (curTime-lastPointAdded>5*24*60*60*1000 && curTime<=new Date().getTime()) {  
      chart.xAxis[0].removePlotLine("myLine");
      chart.xAxis[0].addPlotLine({id: "myLine", color: "red", width: 1, value: curTime});

      // one chart point every 5 days
      chart.series[0].addPoint({x:curTime, y:numEvents},
          true, false, true); //chart.series[0].data.length>100, true);
      lastPointAdded=curTime;
    }

	  while (maxIndex<events.length-1 && events[maxIndex+1].time<curTime) {
	   // expand interval to the current time
	   maxIndex++;
	  }
	  if (loaded && (maxIndex==minIndex && maxIndex==events.length-1)) {
		window.setTimeout(function() {
  	        timeDirection=-1;
		    processing.loop();
		}, 30000);
		processing.noLoop();
	    return;
	  }
	  processing.background( bg );
	  processing.fill(255, 255, 255, 255);
	  processing.stroke(255, 255, 255, 255);
	  processing.strokeWeight(1);
	  for (var c in chaptersOnMap) {
	      processing.drawChapter(c, chaptersOnMap[c]);
	  }
	  processing.noFill();
	  
	  for (var i=minIndex; i<=maxIndex; i++) {
	    if (events[i].steps>numberOfFrames) {
    		// skip events that were faded out
  		  minIndex=i;
	    } else {
		    var chapter=chapters[events[i].chapterId];
		    if (!chapter.firstEvent) chapter.firstEvent=events[i];
		    chaptersOnMap[events[i].chapterId]=chapter;
		    var coords=processing.getCoordinates(chapter);
	      if (events[i].steps==0) {
	        numEvents++;
        }
		    events[i].steps++;
		    var sw=8;
		    var radius = maxRadius*(events[i].steps/numberOfFrames);
		    while (radius>8) {
		      processing.stroke(224, 20, 20, 200-190*events[i].steps/numberOfFrames);
		      processing.strokeWeight(8-sw);
		      sw=Math.max(1,sw-2);
		      processing.ellipse( coords.x, coords.y, radius, radius );
		      radius=radius-12;
		    }
	    }
	  }

	  if (curTime<=_today) {
	    curTime+=24*60*60*1000; // append one more day
	  }
	}


  processing.removeChapter=function(id, chapter) {
    smallEarth.removePoint(id);
    chapter.addedToEarth=false;
    numChaptersAdded--;
  }

	processing.reverseLoop=function() { 
	  updateLabels();
	  
    chart.xAxis[0].removePlotLine("myLine");
    chart.xAxis[0].addPlotLine({id: "myLine", color: "red", width: 1, value: curTime});
    
	  processing.background( bg );
	  processing.fill(255, 255, 255, 255);
	  processing.stroke(255, 255, 255, 255);
	  processing.strokeWeight(1);
	  for (var c in chaptersOnMap) {
	    if (chaptersOnMap[c].firstEvent.time<curTime) {
	      processing.drawChapter(c, chaptersOnMap[c]);
	    } else if (chaptersOnMap[c].addedToEarth) {
	      processing.removeChapter(c, chaptersOnMap[c]);
      }
	  }
	  for (var i=events.length-1; i>=0 && events[i].time>=curTime; i--) {
	    if (events[i].steps!=0) {
        events[i].steps=0;
        numEvents--;
      }
	  }
	  
	  if (numChaptersAdded==0) {
      chart.xAxis[0].removePlotLine("myLine");
      chart.series[0].setData([],false);
	    initVars();
	    timeDirection=1;
	    return;
    }	  
	  curTime-=10*24*60*60*1000; // remove ten more days
  };

}

var processingInstance;
$('document').ready(function() {
  var screenHeight=window.screen.height;
  var availableHeights=[1080, 768];
  var imageHeights=[523, 372];
  var imageWidths=[985, 700];
  var index=0;
  while (index<availableHeights.length-1 && availableHeights[index]>screenHeight) {
    index++;
  }
  map_bg_height=availableHeights[index];
  map_height=imageHeights[index];
  map_width=imageWidths[index];

  $('#outerEarth').hide();
  
  $('#map3dBig').css('width', Math.round(window.innerWidth*0.70)+"px");
  $('#map3d').css('width', (Math.round(map_width)*0.6)+"px");
  $('#map3d').css('height', map_height+"px");
  
  $('#container').css('width', map_width+"px");
  $('#outer').css('width', (Math.round(map_width)*1.6+50)+"px");
  $('#info').css('width', (Math.round(map_width)*1.6)+"px");

  $('#container').css('width', map_width+"px");
  $('#outer').css('width', (Math.round(map_width)*1.6+50)+"px");
  
	processingInstance = new Processing(document.getElementById("map"), sketch);
  $('#clickhandler').toggle(
    function() {showChapterList();},
    function() {showEventVisualization();});
});

var savedTimeDirection=0;

function showEventVisualization() {
    timeDirection=savedTimeDirection;
    savedTimeDirection=0;
	$('#clickhandler').removeClass('chapterList');
	$('#clickhandler>div').text('Touch the screen to navigate using Google Earth');
	$('#outerEarth').fadeOut('fast', function() {
		$('#outer').fadeIn('fast');
	});
}

function showChapterList() {
    savedTimeDirection=timeDirection;
    timeDirection=0;
  	$('#clickhandler').addClass('chapterList');
    $('#clickhandler>div').text('Touch here to go back to events visualization');
    $('#outer').fadeOut('fast', function() {
		$('#outerEarth').fadeIn('fast', function() {
			maybeInitializeChapterEarth();
		});
	});
}

